import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;


public class InformationGain {
	public static final int Type = 0;
	public static final int LifeStyle = 1;
	public static final int Vacation = 2;
	public static final int eCredit = 3;
	public static final int Salary = 4;
	public static final int Property = 5;
	public static final int Class = 6;
	private static HashMap<Integer,ArrayList<String>> AttributeValue;
	
	public InformationGain(){
		AttributeValue = new InitialAttribute().getAttributeValue();
	}
	
	/**
	 * 
	 * @param setOfExamples
	 * @param attribute
	 * @param value
	 * @return
	 */
	public HashMap<String,Integer> countExamples(ArrayList<Data> setOfExamples,int attribute,String value){
		int C1 = 0,C2 = 0,C3 = 0,C4 = 0,C5 = 0;
		HashMap<String,Integer> numberOfExample = new HashMap<String,Integer>();
		ArrayList<Data> count = new ArrayList<Data>();
		count = setOfExamples;
		for(int i = 0;i<count.size();i++){
			if(count.get(i).getAttribute(attribute).equals(value)){
			   if(count.get(i).getAttribute(InformationGain.Class).equals("C1")){
				   C1++;
			   }
			   if(count.get(i).getAttribute(InformationGain.Class).equals("C2")){
				   C2++;
			   }
			   if(count.get(i).getAttribute(InformationGain.Class).equals("C3")){
				   C3++;
			   }
			   if(count.get(i).getAttribute(InformationGain.Class).equals("C4")){
				   C4++;
			   }
			   if(count.get(i).getAttribute(InformationGain.Class).equals("C5")){
				   C5++;
			   }
			}
		}
		numberOfExample.put("C1", C1);
		numberOfExample.put("C2", C2);
		numberOfExample.put("C3", C3);
		numberOfExample.put("C4", C4);
		numberOfExample.put("C5", C5);
		return numberOfExample;
	}
	
	/**
	 * To count the number of examples
	 * @param setOfExamples
	 * @return HashMap which stores the number of examples in different class
	 */
	public HashMap<String,Integer> countExamples(ArrayList<Data> setOfExamples){
		int C1 = 0,C2 = 0,C3 = 0,C4 = 0,C5 = 0;
		HashMap<String,Integer> numberOfExample = new HashMap<String,Integer>();
		ArrayList<Data> count = new ArrayList<Data>();
		count = setOfExamples;
		for(int i = 0;i<count.size();i++){
			if(count.get(i).getAttribute(Class).equals("C1")){
				C1++;
			}
			if(count.get(i).getAttribute(Class).equals("C2")){
				C2++;
			}
			if(count.get(i).getAttribute(Class).equals("C3")){
				C3++;
			}
			if(count.get(i).getAttribute(Class).equals("C4")){
				C4++;
			}
			if(count.get(i).getAttribute(Class).equals("C5")){
				C5++;
			}
		}
		numberOfExample.put("C1", C1);
		numberOfExample.put("C2", C2);
		numberOfExample.put("C3", C3);
		numberOfExample.put("C4", C4);
		numberOfExample.put("C5", C5);
		return numberOfExample;
	}
	
	/**
	 * To calculate the entropy
	 * @param setOfExamples
	 */
	public double entropy(ArrayList<Data> setOfExamples){
		double totalExample;
		double numberOfC1;
		double numberOfC2;
		double numberOfC3;
		double numberOfC4;
		double numberOfC5;
		double C1term;
		double C2term;
		double C3term;
		double C4term;
		double C5term;
		
		HashMap<String,Integer> countResult = countExamples(setOfExamples);
		numberOfC1 = countResult.get("C1");
		numberOfC2 = countResult.get("C2");
		numberOfC3 = countResult.get("C3");
		numberOfC4 = countResult.get("C4");
		numberOfC5 = countResult.get("C5");
		totalExample = numberOfC1+numberOfC2+numberOfC3+numberOfC4+numberOfC5;
		
		if(numberOfC1 !=0){
			C1term = -(numberOfC1/totalExample)*log(numberOfC1/totalExample);
		} else C1term = 0;
		
		if(numberOfC2 !=0){
			C2term = -(numberOfC2/totalExample)*log(numberOfC2/totalExample);
		} else C2term = 0;
		
		if(numberOfC3 !=0){
			C3term = -(numberOfC3/totalExample)*log(numberOfC3/totalExample);
		} else C3term = 0;
		
		if(numberOfC4 !=0){
			C4term = -(numberOfC4/totalExample)*log(numberOfC4/totalExample);
		} else C4term = 0;
		
		if(numberOfC5 !=0){
			C5term = -(numberOfC5/totalExample)*log(numberOfC5/totalExample);
		} else C5term = 0;
		
		
		return C1term+C2term+C3term+C4term+C5term;
		
	}
	
	/**
	 * Calculate the log based 2
	 * @param number
	 * @return
	 */
	public double log(double number){
		return Math.log10(number)/Math.log10(2);
	}
	
	public double getGain(ArrayList<Data> setOfExamples, int attribute){
		double entropyS = entropy(setOfExamples);
		double secondTerm = 0;
		int numberOfValues = AttributeValue.get(attribute).size();
		
		//////////////////////////////////////////////
		//System.out.println("total entropy: "+entropyS);
		//System.out.println("numberOfValues: "+numberOfValues);
		
		// To calculate the second part of InformationGain formular
		for(int i = 0; i< numberOfValues;i++){
		   String particularValue = AttributeValue.get(attribute).get(i);
		   double propotionResult = propotion(setOfExamples,attribute,particularValue);// Sv/S
		   
		   ////////////////////////////////////////////
		   //System.out.println("propotionResult: "+propotionResult);
		   
		   ArrayList<Data> subSetOfExamples = getSubSetOfExamples(setOfExamples,attribute,particularValue);
		  
		   ////////////////////////////////////////////
		   //System.out.println("size of subSetOfExamples: "+subSetOfExamples.size());
		   
		   double entropySv =  entropy(subSetOfExamples);
		   
		   ////////////////////////////////////////////
		   //System.out.println("entropySv: "+entropySv);
		   
		   secondTerm += propotionResult*entropySv;
		}
		return entropyS-secondTerm;
	}
	
	
	/**
	 * To get the sub set of examples which belongs to particular attribute with the particular value
	 * @param setOfExamples
	 * @param attribute
	 * @param value
	 * @return
	 */
	public ArrayList<Data> getSubSetOfExamples(ArrayList<Data> setOfExamples,int attribute, String value){
		ArrayList<Data> subSetOfExamples = new ArrayList<Data>();
		for(int i=0;i<setOfExamples.size();i++){
			if(setOfExamples.get(i).getAttribute(attribute).equals(value)){
				subSetOfExamples.add(setOfExamples.get(i));
			}
		}
		return subSetOfExamples;
	}
	/**
	 * To calculate the propotion of the Sv and S
	 * @param setOfExamples
	 * @param attribute
	 * @param value
	 * @return
	 */
	public double propotion(ArrayList<Data> setOfExamples, int attribute, String value){
		double Sv = 0;
		double S = 0; 
		HashMap<String,Integer> SvMap = countExamples(setOfExamples,attribute,value);
		HashMap<String,Integer> SMap = countExamples(setOfExamples);
		Iterator<Integer> iterSv = SvMap.values().iterator();
		Iterator<Integer> iterS = SMap.values().iterator();
		
		while(iterSv.hasNext()){
			Sv += iterSv.next();
		}
		while(iterS.hasNext()){
			S += iterS.next();
		}
		
		//////////////////////////////////////////////////
		//System.out.println("number of Sv: "+ Sv);
		//System.out.println("number of S: "+ S);
		
		return Sv/S;
	}
	
	
}
